/**   
* @Title: FaceUtilits.java 
* @Package net.gdface.utils 
* @Description: guyadong 
* @author guyadong   
* @date 2014-10-21 上午10:51:32 
* @version V1.0   
*/
package net.gdface.utils;

import java.lang.reflect.MalformedParameterizedTypeException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * 类型工具(反射)
 * @author guyadong
 *
 */
public class SimpleTypes {
	/**
	 * 返回{@code clazz}泛型超类的参数对象<br>
	 * 如果无法获取泛型参数对象，返回null
	 * @param clazz
	 * @return 参数类型数组
	 * @see #getParameterizedType(Class)
	 */
	public static  Class<?>[] getParameterizedTypeNoThrow(Class<?>clazz) {
		try{
		Class<?>[] types=getParameterizedType(clazz);
		return types;
		}catch(Exception e){
			return null;
		}
	}
	/**
	 * 返回{@code clazz}泛型超类的参数对象<br>
	 * 如果超类不是泛型对象，则抛出{@link IllegalArgumentException}<br>
	 * @param clazz
	 * @return 参数类型数组
	 * @throws MalformedParameterizedTypeException 无法获取实际泛型参数对象类型
	 * @throws IllegalArgumentException 超类不是泛型类
	 */
	public static  Class<?>[] getParameterizedType(Class<?>clazz) throws MalformedParameterizedTypeException, IllegalArgumentException{
		Type superType = clazz.getGenericSuperclass();
		if(!(superType instanceof ParameterizedType)){
			//超类不是泛型
			throw new IllegalArgumentException(String.format("superclass of %s  not ParameterizedType(超类不是泛型类)",clazz.getName()));
		}
		Type[] types = ((ParameterizedType) superType).getActualTypeArguments();		
		Class<?>[] paramClass=new Class<?>[types.length];
		for(int i=0;i<paramClass.length;i++){
			if(!(types[i] instanceof Class<?>)){
				System.err.printf("cant'not get class for ParameterizedType (无法获取实际泛型参数对象类型(Class)) %s",types[i]);
				throw new MalformedParameterizedTypeException();
			} 
			paramClass[i]=(Class<?>)types[i];
		}
		return paramClass;		
	}

	/**
	 * 以递归方式返回指定类型({@link Type})的原始类型<br>
	 * @param type
	 * @return Class 实例
	 * @throws IllegalArgumentException type 非 Class 或 ParameterizedType,无法获取原始类型
	 */
	public static final Class<?> getRawClass(Type type){
	    if(type instanceof Class<?>){
	        return (Class<?>) type;
	    } else if(type instanceof ParameterizedType){
	        return getRawClass(((ParameterizedType) type).getRawType());
	    } else{
	        throw new IllegalArgumentException(String.format("invalid type %s", type));
	    }
	}
	/**
	 * 返回{@code type}的父类泛型参数的原始类型
	 * @param type 
	 * @return 原始类型数组
	 * @throws IllegalArgumentException type 非 Class 或 ParameterizedType,无法获取原始类型
	 */
	public static final Class<?>[] getRawClassOfSuperPamamType(Class<?>type){
		Type superType = type.getGenericSuperclass();
		if(!(superType instanceof ParameterizedType)){
			//超类不是泛型
			throw new IllegalArgumentException(String.format("superclass of %s  not ParameterizedType(超类不是泛型类)",type.getName()));
		}
		Type[] types = ((ParameterizedType) superType).getActualTypeArguments();		
		Class<?>[] paramClass = new Class<?>[types.length];
		for(int i=0; i<paramClass.length; i++){
			paramClass[i] = getRawClass(types[i]);
		}
		return paramClass;		
	}
	/**
	 * 返回{@code obj}的父类泛型参数的原始类型
	 * @param obj
	 * @return 原始类型数组
	 */
	public static final Class<?>[] getRawClassOfSuperPamamType(Object obj){
		return getRawClassOfSuperPamamType(obj.getClass());
	}
	/**
	 * 返回导致异常的原因(cause)
	 * @param e
	 * @return Throwable object or e if cause is null
	 */
	public final static Throwable getCause(Throwable e) {
		return e==null?null:(e.getCause()==null?e:e.getCause());
	}

	/**
	 * 以递归方式返回被{@code shellClass}多层封装的异常<br>
	 * @param e
	 * @param shellClass 封装异常的类
	 * @return 剥离外层封装的异常对象
	 */
	public static final Throwable stripThrowableShell(Throwable e, Class<? extends Throwable> shellClass){
		if(!Judge.hasNull(e,e.getCause())&&e.getClass()==shellClass){
			return stripThrowableShell(e.getCause(), shellClass);
		}
		return e;
	}
    /**
	 * 递归方式判断一个{@link RuntimeException}异常的原因是不是来自网络通信异常(超时，连接错误) <br>
	 * {@link java.net.SocketTimeoutException},{@link java.net.ConnectException}<br>
	 * @param e
	 * @return true/false
	 */
	public static final boolean isNetworkError(Throwable e) {
		return (e instanceof java.net.SocketTimeoutException || e instanceof java.net.ConnectException)
				|| (null != e && isNetworkError(e.getCause()));
	}
}
